# -*- coding: utf-8 -*-
#   单据转换成pdf文件基类
# @Time    ： 2024/2/13  17:10
# @Auther  ： 徐良
# File     :  billToPdfBase.py
from typing import Dict, Any
from PySide6.QtCore import QObject, Signal
from reportlab.pdfbase import pdfmetrics  # 注册字体
from reportlab.pdfbase.ttfonts import TTFont  # 字体类
from rlextra.rml2pdf import rml2pdf
import preppy
import share.globalvar as gol
from utils.printServer import PDFPreviewAndPrint
from baseClass.tools.tableToList import TableToListDict
from utils.QRcodeApp import QRcodeApp
from share.dataFactory import DataFactory
import os
import re


class BillToPdfBase(QObject):
    """
    单据转换为pdf文件的基类
    """
    pdfGenerated = Signal(dict)

    def __init__(self):
        super(BillToPdfBase, self).__init__()
        self.currentP = gol.get_value('currentPath')  # 获取应用程序的路经
        self.logo_path = self.currentP + '/resource/images/蔚蓝.png'
        self.company_name = '上海禾鼎食品工业有限公司'
        self.prepTemplateName = None  # prep模板文件名称(包含路经)

        # 默认审核章，合格章，不合格章的路经
        self.auditSeal = self.currentP + '/resource/stamp/审核图章.png'
        self.qualificationSeal = self.currentP + '/resource/stamp/合格图章.png'
        self.disqualificationSeal = self.currentP + '/resource/stamp/不合格图章.png'

        self.pdfName = None  # 生成的pdf文件名称(包含路经)
        self.temporaryDir = None  # 临时工作目录
        self.QR_imgPath = None
        self.reportName = ''  # 报表名称
        self.msFNumber = None  # 模块编号
        self.dataDict = None
        self.hTableName = None  # 表头数据表名
        self.bTableName = None  # 表体数据表名
        self.dateName = 'fdate'  # 默认的日期字段名      字段名要小写
        self.billNoName = 'fbillno'  # 默认的单据编号字段名
        self.numberName = 'fnumber'  # 默认的物料代码字段名
        self.itemName = 'fname'         # 默认表头name字段名
        self.image_path = '/temporary'  # 默认图片存放目录
        self.defaultPdfName = None
        self.__register_chinese_font()  # 注册字体

    def check_file_exists(self, filepath):
        """
        检查文件是否存在
        :param filepath:
        :return:
        """
        return os.path.exists(filepath)

    def process_string(self, s):
        pattern = r'([^v]*)-v(\d+)\.pdf'
        match = re.match(pattern, s, re.IGNORECASE)

        if match:
            before_v = match.group(1).strip()
            v = int(match.group(2))

            return [before_v, v]
        else:
            return None

    def find_pdf_files(self, directory):
        """
        获取指定目录下所有pdf文件
        :param directory:
        :return:
        """
        pdf_files = []
        for root, dirs, files in os.walk(directory):
            for file in files:
                if file.lower().endswith('.pdf'):
                    pdf_files.append(os.path.join(root, file))
        return pdf_files

    def split_path(self, filepath):
        return os.path.split(filepath)

    def extract_version_number(self, file_path):
        """
        获取字符串_V后的数字
        :param file_path:
        :return:
        """
        match = re.search(r'_V(\d+)', file_path)
        if match:
            version_number = match.group(1)
            return int(version_number)
        else:
            return None

    def extract_before_V(self, string):
        """
        获取文件名不包括V之后的数字
        :param string:
        :return:
        """
        match = re.search(r'(.+)_V\d+', string)
        if match:
            return match.group(1)
        else:
            return None

    def getNewPdfNameV(self, filePath):
        """
        获取新的文件名
        :param filePath:
        :return:
        """
        directory, filename = self.split_path(filePath)
        # 获取指定目录下所有文件
        fList = self.find_pdf_files(directory)
        vList = []
        for ss in fList:
            v = self.extract_version_number(ss)
            if v is not None:
                vList.append(v)

        max_value = max(vList) + 1

        sn = self.extract_before_V(filename)
        ret = directory + '/' + sn + '_V' + str(max_value) + '.pdf'
        return ret

    def removeFile(self, fname):
        if os.path.exists(fname):
            try:
                os.remove(fname)
            except Exception as e:
                print(f"An error occurred while deleting the file: {str(e)}")

    def __register_chinese_font(self):
        """
        注册中文字体
        :return:
        """
        font_path = self.currentP + "/font/simsun.ttc"  # 使用绝对路径指定字体文件的位置
        pdfmetrics.registerFont(TTFont('simsun', font_path))
        font_path = self.currentP + "/font/msyhbd.ttc"  # 使用绝对路径指定字体文件的位置
        pdfmetrics.registerFont(TTFont('msyhbd', font_path))
        font_path = self.currentP + "/font/msyh.ttc"  # 使用绝对路径指定字体文件的位置
        pdfmetrics.registerFont(TTFont('msyh', font_path))

    def __getFilePathInfo(self, msFnum):
        """
        获取pdf文件字段信息
        :param msFnum: 模块编码
        :return:字典
        """
        # 新代码满足多个FModelNumber对应一个文件目录
        sql = "SELECT * FROM t_billpdfpath WHERE  FIND_IN_SET('{sFNum}', " \
              "REPLACE(FModelNumber, '，', ',')) > 0;".format(sFNum=msFnum)

        model = DataFactory.getQueryModelForSql(sql)
        record = model.record(0)

        FPath = record.value('FPath')                       # 保存文件的根路经
        FFolderType = record.value('FFolderType')           # 文件夹类型 两种：固定和变化
        FFolderClassification = record.value('FFolderClassification')   # 文件夹分类方式， 四种：无，年-月-日，年，年-月
        FIsPre = record.value('FIsPre')         # 是否使用单据前缀
        FBillPre = record.value('FBillPre')     # 单据名称前缀
        FIsField = record.value('FIsField')     # 是否使用字段前缀
        FFields = record.value('FFields')       # 字段前缀的内容，以‘,’分割

        ret = {'FPath': FPath, 'FFolderType': FFolderType, 'FFolderClassification': FFolderClassification,
               'FIsPre': FIsPre, 'FBillPre': FBillPre, 'FIsField': FIsField, 'FFields': FFields}
        return ret

    def __getDateStrByYMD(self, sDate, sCondi):
        """
        根据给定的条件，如年， 年， 年-月， 年-月-日，返回相应格式字符串yyyy, yyyy-mm, yyyy-mm-dd
        :param sDate:
        :param sCondi:
        :return:
        """
        sd8 = sDate[0:10]
        sList = sd8.split("-")
        if sCondi == '年':
            ret = sList[0]
        elif sCondi == '年-月':
            ret = sList[0] + '-' + sList[1]
        elif sCondi == '年-月-日':
            ret = sList[0] + '-' + sList[1] + '-' + sList[2]
        else:
            ret = ''
        return ret

    def __getFilePathStr(self, base_path, sDate):
        """
        根据给出日期字符串，判断该字符串对应的文件夹是否存在，如存在则返回全路径，如不存在则创建并返回全路径
        :param sDate: 如2023，2023-11，2023-11-10，返回路经字符串
        :param base_path: 给定的文件夹
        :return:
        """
        # 将日期字符串按需拆分为年、月、日
        sd8 = sDate[0:10]
        date_parts = sd8.split("-")
        year, month, day = date_parts + [None] * (3 - len(date_parts))  # 填充缺少的部分为 None

        # 构建文件夹路径
        year_path = os.path.join(base_path, f"{year}年") if year else base_path
        month_path = os.path.join(year_path, f"{month}月") if month else year_path
        day_path = os.path.join(month_path, f"{day}日") if day else month_path

        # 检查并创建文件夹
        if not os.path.exists(year_path) and year:
            os.makedirs(year_path)

        if not os.path.exists(month_path) and month:
            os.makedirs(month_path)

        if not os.path.exists(day_path) and day:
            os.makedirs(day_path)

        # 返回完整路径
        if os.path.exists(day_path) and day:
            return day_path

    def __parserFileName(self, pathInfoDict, hDict):
        """
        解析文件名的名称
        :param pathInfoDict: 文件保存路经的信息
        :return:
        """
        sList = []
        if pathInfoDict['FIsPre']:              # 如果要求有单据名称的前缀
            sList.append(pathInfoDict['FBillPre'])

        if pathInfoDict['FIsField']:            # 如果要有字段名内容的前缀
            fList = pathInfoDict['FFields'].split(',')
            for obj in fList:
                nn = obj.lower()
                if nn in hDict:
                    v = hDict[nn]
                    if v is not None and v != '':
                        sList.append(v)

        # 要增加是否有变化的路经
        if pathInfoDict['FFolderType'] == '固定':
            ret = pathInfoDict['FPath'] + '/' + '_'.join(sList) + '_V1.pdf'
        else:
            sDate = hDict[self.dateName]
            # 获取文件定义的日期的格式，三种：年-月-日；年-月，年
            ssDate = self.__getDateStrByYMD(sDate, pathInfoDict['FFolderClassification'])

            # 获取带日期目录的路经
            ssfpath = self.__getFilePathStr(pathInfoDict['FPath'], ssDate)
            ret = ssfpath + '/' + '_'.join(sList) + '_V1.pdf'
        return ret

    def __getFileFullPath(self, msFNum, hDict):
        """
        获取包含文件的根路经
        :param hDict: 表单的当前记录
        :param msFNum: 模块编码
        :return: str
        """
        pathInfoDict = self.__getFilePathInfo(msFNum)
        fullFileName = self.__parserFileName(pathInfoDict, hDict)
        return fullFileName

    def __getPdfFile(self):
        """
        根据self.pdfName（文件名称，完整路经）,生成pdf文件
        :return:
        """
        self.dataDict['reportName'] = self.reportName
        self.dataDict['QR_imgPath'] = self.QR_imgPath
        self.dataDict['logoPath'] = self.logoPath

        self.dataDict['auditSeal'] = self.auditSeal
        self.dataDict['qualificationSeal'] = self.qualificationSeal
        self.dataDict['disqualificationSeal'] = self.disqualificationSeal

        prepFile = self.currentP + '/' + self.prepTemplateName  # 模板文件
        source_text = open(prepFile, encoding='utf-8').read()

        template = preppy.getModule(prepFile, sourcetext=source_text)
        rmlText = template.get(self.dataDict)  # 模板需要的参数，字典形式
        rml2pdf.go(rmlText, outputFileName=self.pdfName)
        return True

    def __getHBDataListDict(self, sid):
        """
        获取单据表头表头数据，字典格式， hDict 为表头字典数字，bList为表头字典列表
        :param sid:
        :return:
        """

        hsql = "select * from {tName} where fid={sFid}".format(sFid=str(sid), tName=self.hTableName)
        tToL = TableToListDict(hsql)
        hDict = tToL.getListDict()[0]
        ret = {'hDict': hDict}  # 表头

        bsql = "select * from {tName} where Fentityid={sFid}".format(sFid=str(sid), tName=self.bTableName)
        tToL = TableToListDict(bsql)
        dList = tToL.getListDict()  # 表体
        ret['bList'] = dList
        return ret

    def __setDefaultName(self, pDic):
        """
        设置 默认的日期字段名，单据编号字段名， 物料代码字段名， 默认图片存放目录
        :param pDic:
        :return:
        """
        if 'dateName' in pDic:  # 单据日期字段名称
            self.dateName = pDic['dateName'].lower()

        if 'billNoName' in pDic:  # 单据编号字段名称
            self.billNoName = pDic['billNoName'].lower()

        if 'numberName' in pDic:  # 物料代码字段名称
            self.numberName = pDic['numberName'].lower()

        if 'itemName' in pDic:  # 物料代码字段名称
            self.itemName = pDic['itemName'].lower()

        if 'image_path' in pDic:  # 默认图片存放目录
            self.numberName = pDic['image_path'].lower()

        if 'defaultPdfName' in pDic:  # 默认图片存放目录
            self.defaultPdfName = pDic['defaultPdfName'].lower()

        if 'qualificationSeal' in pDic:  # 默认合格图章存放目录
            self.qualificationSeal = self.currentP + pDic['qualificationSeal'].lower()

        if 'disqualificationSeal' in pDic:  # 默认不合格图章存放目录
            self.disqualificationSeal = self.currentP + pDic['disqualificationSeal'].lower()

        self.defaultPdfName = self.currentP + self.image_path + '/billTemp.pdf'

    def __getBill_QRimage(self, pdic):
        """
        获取二维码图片, 二维码内容， 单据名称，单据内码，物料代码，物料名称
        :param pdic: 表头字段
        :return:
        """

        sList = [self.reportName, str(pdic['fid']), pdic[self.numberName], pdic[self.itemName]]
        sPath = self.currentP + self.image_path + '/QR_' + pdic['fname'] + '.png'
        qr = QRcodeApp()
        qr.saveToPng(sList=sList, sPath=sPath)  # 保存产品二维码文件
        return sPath

    def makeBillPdfFileNoQR(self):
        """
        生成单据，有表头和表体的pdf文件   不需要生成二维码
        :return:
        """
        pass

    def makeBillPdfFileHasQr(self, pDic):
        """
        生成单据，有表头和表体的pdf文件   需要生成二维码
        :param pDic:    表头数据表名，表体数据表名，报表名称，表头的id列表，模板名称，
                        模块代码
        :return:
        """
        idList = pDic['idList']
        self.__setDefaultName(pDic)  # 设置默认值
        for xId in idList:
            self.msFNumber = pDic['msFNumber']  # 模块编号
            self.hTableName = pDic['hTableName']  # 表头数据表名
            self.bTableName = pDic['bTableName']  # 表体数据表名
            self.reportName = pDic['reportName']  # 报表名称

            if 'prepTemplateName' in pDic:
                self.prepTemplateName = pDic['prepTemplateName']
            if 'logoPath' in pDic:
                self.logoPath = pDic['logoPath']

            self.dataDict = self.__getHBDataListDict(str(xId))
            self.QR_imgPath = self.__getBill_QRimage(self.dataDict['hDict'])  # 获取单据的二维码图片，并存放在指定路经
            self.pdfName = self.__getFileFullPath(self.msFNumber, self.dataDict['hDict'])

            if self.check_file_exists(self.pdfName):
                newpdfName = self.getNewPdfNameV(self.pdfName)
                self.pdfName = newpdfName

            self.__getPdfFile()
        self.pdfGenerated.emit({'ok': 'ok', 'inf': '完成pdf文件保存'})

    def toPreviewBillHasQr(self, pDic):
        """
        打印预览表单文件
        :param pDic:
        :return:
        """
        idList = pDic['idList']
        self.__setDefaultName(pDic)  # 设置默认值

        if 'msFNumber' in pDic:
            self.msFNumber = pDic['msFNumber']  # 模块编号
        self.hTableName = pDic['hTableName']  # 表头数据表名
        self.bTableName = pDic['bTableName']  # 表体数据表名
        self.reportName = pDic['reportName']  # 报表名称

        if 'prepTemplateName' in pDic:
            self.prepTemplateName = pDic['prepTemplateName']
        if 'logoPath' in pDic:
            self.logoPath = pDic['logoPath']

        self.dataDict = self.__getHBDataListDict(str(idList[0]))
        self.QR_imgPath = self.__getBill_QRimage(self.dataDict['hDict'])  # 获取单据的二维码图片，并存放在指定路经
        self.pdfName = self.defaultPdfName
        self.__getPdfFile()

        preview = PDFPreviewAndPrint(self.pdfName, pDic['parent'])
        preview.preview_pdf()
        self.removeFile(self.pdfName)

    def toPreviewBillNoQr(self, pDic):
        """
        没有二维码
        :param pDic:
        :return:
        """
        idList = pDic['idList']
        self.__setDefaultName(pDic)  # 设置默认值

        if 'msFNumber' in pDic:
            self.msFNumber = pDic['msFNumber']  # 模块编号
        self.hTableName = pDic['hTableName']  # 表头数据表名
        self.bTableName = pDic['bTableName']  # 表体数据表名
        self.reportName = pDic['reportName']  # 报表名称

        if 'prepTemplateName' in pDic:
            self.prepTemplateName = pDic['prepTemplateName']
        if 'logoPath' in pDic:
            self.logoPath = pDic['logoPath']

        self.dataDict = self.__getHBDataListDict(str(idList[0]))
        self.pdfName = self.defaultPdfName
        self.__getPdfFile()

        preview = PDFPreviewAndPrint(self.pdfName, pDic['parent'])
        preview.preview_pdf()
        self.removeFile(self.pdfName)

    def toPrintBillNoQr(self, pDic):
        """
        打印表单文件，无二维码
        :param pDic:
        :return:
        """
        idList = pDic['idList']
        self.__setDefaultName(pDic)  # 设置默认值

        for sid in idList:
            if 'msFNumber' in pDic:
                self.msFNumber = pDic['msFNumber']  # 模块编号

            self.hTableName = pDic['hTableName']  # 表头数据表名
            self.bTableName = pDic['bTableName']  # 表体数据表名
            self.reportName = pDic['reportName']  # 报表名称

            if 'prepTemplateName' in pDic:
                self.prepTemplateName = pDic['prepTemplateName']
            if 'logoPath' in pDic:
                self.logoPath = pDic['logoPath']

            self.dataDict = self.__getHBDataListDict(str(idList[0]))
            self.pdfName = self.defaultPdfName
            self.__getPdfFile()

            preview = PDFPreviewAndPrint(self.pdfName)
            preview.print_printPdf()
            self.removeFile(self.pdfName)

        self.pdfGenerated.emit({'ok': 'ok', 'inf': '完成pdf文件打印'})

    def toPrintBillHasQr(self, pDic):
        """
        打印表单文件
        :param pDic:
        :return:
        """
        idList = pDic['idList']
        self.__setDefaultName(pDic)  # 设置默认值

        for sid in idList:
            if 'msFNumber' in pDic:
                self.msFNumber = pDic['msFNumber']  # 模块编号

            self.hTableName = pDic['hTableName']  # 表头数据表名
            self.bTableName = pDic['bTableName']  # 表体数据表名
            self.reportName = pDic['reportName']  # 报表名称

            if 'prepTemplateName' in pDic:
                self.prepTemplateName = pDic['prepTemplateName']
            if 'logoPath' in pDic:
                self.logoPath = pDic['logoPath']

            self.dataDict = self.__getHBDataListDict(str(idList[0]))
            self.QR_imgPath = self.__getBill_QRimage(self.dataDict['hDict'])  # 获取单据的二维码图片，并存放在指定路经
            self.pdfName = self.defaultPdfName
            self.__getPdfFile()


            preview = PDFPreviewAndPrint(self.pdfName)
            preview.print_printPdf()
            self.removeFile(self.pdfName)

        self.pdfGenerated.emit({'ok': 'ok', 'inf': '完成pdf文件打印'})



    # region 针对制造计划，制造排程
    def toPreviewForPlan(self, pDict):
        """
        计划和排程
        :param pDict:
        :return:
        """
        pDict['logo_image'] = self.logoPath

        prepFile = self.currentP + '/' + pDict['pdfTemp']  # 模板文件
        pdfName = self.currentP + '/' + pDict['tempName'] + '/' + pDict['planName'] + '.pdf'    # 目标文件

        source_text = open(prepFile, encoding='utf-8').read()

        template = preppy.getModule(prepFile, sourcetext=source_text)
        rmlText = template.get(pDict)  # 模板需要的参数，字典形式
        rml2pdf.go(rmlText, outputFileName=pdfName)

        preview = PDFPreviewAndPrint(pdfName, pDict['parent'])
        preview.preview_pdf()

    def to_print_aps(self, params_dict: Dict[str, Any]):
        """
        计划和排程
        :param pDict:
        :return:
        """
        params_dict['company_name'] = self.company_name
        params_dict['logo_path'] = self.logo_path

        prepFile = self.currentP + '/' + params_dict['pdf_temp']  # 模板文件
        pdf_name = self.currentP + '/' + params_dict['temp_directory'] + '/' + params_dict['pdf_name'] + '.pdf'    # 目标文件

        source_text = open(prepFile, encoding='utf-8').read()

        template = preppy.getModule(prepFile, sourcetext=source_text)
        rmlText = template.get(params_dict)  # 模板需要的参数，字典形式
        rml2pdf.go(rmlText, outputFileName=pdf_name)

        preview = PDFPreviewAndPrint(pdf_name)
        preview.print_pdf(direction=1)
        self.removeFile(pdf_name)


    def to_preview_aps(self,params_dict: Dict[str, Any], parant):
        """
        打印预览表单文件
        :param pDic:
        :return:
        """
        params_dict['company_name'] = self.company_name
        params_dict['logo_path'] = self.logo_path
        prep_file = self.currentP + '/' + params_dict['pdf_temp']  # 模板文件
        pdf_name = self.currentP + '/' + params_dict['temp_directory'] + '/'+ params_dict['pdf_name'] + '.pdf'    # 目标文件

        source_text = open(prep_file, encoding='utf-8').read()

        template = preppy.getModule(prep_file, sourcetext=source_text)
        rmlText = template.get(params_dict)  # 模板需要的参数，字典形式
        rml2pdf.go(rmlText, outputFileName=pdf_name)

        preview = PDFPreviewAndPrint(pdf_name, parant)
        preview.preview_pdf(direction=1)    # 横向预览
        # self.removeFile(pdfName)




